package ar.com.spsolutions.splibrary.book;// NOPMD by leezsi on 13/10/11 18:13

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.joda.time.DateTime;

import ar.com.spsolutions.splibrary.author.Author;
import ar.com.spsolutions.splibrary.book.category.Category;
import ar.com.spsolutions.splibrary.book.exceptions.ComemntLengthException;
import ar.com.spsolutions.splibrary.entity.Entity;
import ar.com.spsolutions.splibrary.notifiers.INotifier;
import ar.com.spsolutions.splibrary.user.User;
import ar.com.spsolutions.splibrary.utils.ISBNValidatorUtil;

public class Book extends Entity {
    private static final long serialVersionUID = -8144655446662792292L;

    private String title;

    private String isbn;

    private String publisher;

    private String description;

    private Author author;

    private DateTime timestamp;

    private Set<BookCopy> copies;

    private List<BookComment> comments = new ArrayList<BookComment>();

    private List<Category> categories = new ArrayList<Category>();

    private StarAble starCounter = new StarsCounter();

    private Reserve reserve;

    private INotifier notifier;

    private String pic;

    private Integer loanedTimes;

    public Book() {
        super();
        timestamp = new DateTime();
    }

    public Book(final INotifier aNotifier) {
        this();
        notifier = aNotifier;
        copies = new HashSet<BookCopy>();
        setLoanedTimes(0);
    }

    private void addAvailableCopy(final BookCopy copy) {
        getCopies().add(copy);
        copy.setAvailable(true);
    }

    public void addCategory(final Category aCategory) {
        getCategories().add(aCategory);
        aCategory.addBook(this);
    }

    public void addComment(final User customer, final String comment) throws ComemntLengthException {
        if (comment.length() > 500) {
            throw new ComemntLengthException();
        }
        final BookComment bookComment = new BookComment();
        bookComment.setUser(customer);
        bookComment.setText(comment);
        getComments().add(bookComment);
    }

    public void addFiveStar() {
        getStarCounter().addFiveStar();
    }

    public void addFourStar() {
        getStarCounter().addFourStar();
    }

    public void addOneStar() {
        getStarCounter().addOneStar();
    }

    public void addThreeStar() {
        getStarCounter().addThreeStar();
    }

    public void addTwoStar() {
        getStarCounter().addTwoStar();
    }

    public void createCopies(final int amount) {
        BookCopy copy;
        for (int i = 0; i < amount; i++) {
            copy = new BookCopy();
            copy.setBook(this);
            final int copyId = getCopies().size() + 1;
            copy.setCopyId(getTitle() + "@" + copyId);
            addAvailableCopy(copy);
        }
    }

    public BookCopy getACopy() {
        final Iterator<BookCopy> copyIterator = getCopies().iterator();
        boolean found = false;
        BookCopy bookCopy = null;
        while (copyIterator.hasNext() && !found) {
            bookCopy = copyIterator.next();
            found = bookCopy.isAvailable();
        }
        bookCopy.setAvailable(false);
        return bookCopy;
    }

    private Reserve getActualReserve() {
        // return getReserve() == null ? new Reserve(getNotifier()) :
        // getReserve();
        if (getReserve() == null) {
            setReserve(new Reserve(getNotifier()));
        }
        return getReserve();
    }

    // -----accesors----

    public Author getAuthor() {
        return author;
    }

    public Set<BookCopy> getCopies() {
        return copies;
    }

    public List<Category> getCategories() {
        return categories;
    }

    public List<BookComment> getComments() {
        return comments;
    }

    public String getDescription() {
        return description;
    }

    public String getIsbn() {
        return isbn;
    }

    public INotifier getNotifier() {
        return notifier;
    }

    public String getPic() {
        return pic;
    }

    public Reserve getReserve() {
        return reserve;
    }

    public StarAble getStarCounter() {
        return starCounter;
    }

    public Integer getStars() {
        return getStarCounter().getStars();
    }

    public String getTitle() {
        return title;
    }

    public Integer getVotes() {
        return getStarCounter().getVotes();
    }

    public boolean isAvailable() {
        final Iterator<BookCopy> copyIterator = getCopies().iterator();
        boolean found = false;
        while (copyIterator.hasNext() && !found) {
            found = copyIterator.next().isAvailable();
        }
        return found;
    }

    public void removeCategory(final Category aCategory) {
        getCategories().remove(aCategory);
        aCategory.removeBook(this);
    }

    public LoanBook loanTo(final User customer) {
        final BookCopy aCopy = getACopy();
        final LoanBook loan = new LoanBook(customer, aCopy);
        loan.setNotifier(getNotifier());
        loan.notifyLoan();
        return loan;
    }

    public void reservedFor(final User customer) {
        final Reserve aReserve = getActualReserve();
        aReserve.addBook(this);
        aReserve.addCustomer(customer);
        setReserve(aReserve);
    }

    public void setAuthor(final Author author) {
        this.author = author;
    }

    public void setCopies(final Set<BookCopy> copies) {
        this.copies = copies;
    }

    public void setCategories(final List<Category> categories) {
        this.categories = categories;
    }

    public void setComments(final List<BookComment> comments) {
        this.comments = comments;
    }

    public void setDescription(final String description) {
        this.description = description;
    }

    public void setIsbn(final String isbn) {
        ISBNValidatorUtil.validate(isbn);
        this.isbn = isbn;
    }

    public void setNotifier(final INotifier notifier) {
        this.notifier = notifier;
    }

    public void setPic(final String pic) {
        this.pic = pic;
    }

    public void setReserve(final Reserve reserve) {
        this.reserve = reserve;
    }

    public void setStarCounter(final StarAble starCounter) {
        this.starCounter = starCounter;
    }

    public void setTitle(final String title) {
        this.title = title;
    }

    @Override
    public String toString() {
        return title;
    }

    public void setStars(final Integer stars) {
        starCounter.setStars(stars);
    }

    public Integer getLoanedTimes() {
        return loanedTimes;
    }

    public void setLoanedTimes(final Integer loanedTimes) {
        this.loanedTimes = loanedTimes;
    }

    public void incrementLoanedTimes() {
        setLoanedTimes(getLoanedTimes() + 1);
    }

    public String getPublisher() {
        return publisher;
    }

    public void setPublisher(final String publisher) {
        this.publisher = publisher;
    }

    public Integer getCopiesSize() {
        return getCopies().size();
    }

    public DateTime getTimestamp() {
        return timestamp;
    }

    public void setTimestamp(final DateTime timestamp) {
        this.timestamp = timestamp;
    }

}
